package modules.user.dao;

import java.util.List;
import java.util.Set;

import javax.persistence.Table;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

import modules.user.entity.User;

/*
 * JpaRepository:spring data jpa 默认预先生成了一些基本的CURD的方法，例如：增、删、改等等继承JpaRepository
 * JpaSpecificationExecutor:这个接口是自定义查询，一些不固定的查询。
 */
public interface UserDao extends JpaRepository<User, Long>,JpaSpecificationExecutor<User>{
	//这个public为默认的，可以不写
	/*
	 * spring data jpa 的常用用法。
	 * findByUsername相当于：
	 * select * from User(映射mto_users表) where username = :username
	 * 其中为了识别以username为搜索条件，需要把首字母大写。
	 * 即：findBy + Username。
	 * 其他类推同理
	 */
	public User findByUsername(String username);
	
	User findByEmail(String email);
	
	List<User> findTop12ByOrderByFansDesc();
	
	Page<User> findAllByOrderByDesc(Pageable pageable);
	
	List<User> findAllByIdIn(Set<Long> ids);
	
	@Modifying
	/*
	 * @Modifying注解:
	 * 1、在@Query注解中编写JPQL实现DELETE和UPDATE操作的时候必须加上@modifying注解，以通知Spring Data 这是一个DELETE或UPDATE操作。
	 * 2、UPDATE或者DELETE操作需要使用事务，此时需要 定义Service层，在Service层的方法上添加事务操作。
	 * 3、注意JPQL不支持INSERT操作。　　
	 */
	@Transactional
	/*
	 * 这里直接在dao层添加事务，也可以
	 */
	@Query("update User set posts = posts + :increment where id = :id")
	/*
	 * @Query:查询适用于所查询的数据无法通过关键字查询得到结果的查询
	 * 这种查询可以摆脱像关键字查询那样的约束，将查询直接在相应的接口方法中声明，结构更为清晰，这是Spring Data的特有实现
	 * 这里:increment 是和@Param("increment")注解配合使用的，这样不用管参数的顺序
	 * 
	 * 还有一点，数据库的表是mto_users，为什么这里是update User？
	 * 因为实体类User用了@Entity来映射了该类关联数据库的一个表
	 * 并且@Table(name="mto_users")指定了User 映射的就是mto_users
	 * 所以update User 相当于update mto_users
	 * 注意：User就是实体类的类名
	 */
	int updatePosts(@Param("id") long id,@Param("increment") int increment);
	
	@Modifying
	@Transactional
	@Query("update User set comments = comments + :increment where id = :id")
	int updateComments(@Param("id") long id,@Param("increment") int increment);
	
	@Modifying
	@Transactional
	@Query("update User set follows = follows + :increment where id = :id")
	int updateFollows(@Param("id") long id,@Param("increment") int increment);
	
	@Modifying
	@Transactional
	@Query("update User set fans = fans + :increment where id = :id")
	int updateFans(@Param("id") long id,@Param("increment") int increment);
	
	@Modifying
	@Transactional
	@Query("update User set favors = favors + :increment where id = :id")
	int updateFavors(@Param("id") long id,@Param("increment") int increment);
}
